﻿using Deployment.Data.Deploy.Steps.Tasks;
using System;
using System.Xml.Serialization;


namespace Deployment.Data.Deploy.Steps
{
    public class TaskXmlSerializer<T> : IXmlSerializable where T : AbstractTask
    {
        private const string TYPE_ATTRIB = "Type";
        private const string DESCRIPTION_ATTRIB = "Description";
        private const string ID_ATTRIB = "Id";

        private T _task;

        public TaskXmlSerializer() { }

        public TaskXmlSerializer(T task)
        {
            this.Task = task;
        }

        public T Task
        {
            get { return _task; }
            set { _task = value; }
        }

        #region IXmlSerializable members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            string typeAttibute = reader.GetAttribute(TYPE_ATTRIB);
            string descriptionAttribute = reader.GetAttribute(DESCRIPTION_ATTRIB);
            int idAttribue = int.Parse(reader.GetAttribute(ID_ATTRIB));

            if (string.IsNullOrEmpty(typeAttibute))
                throw new ArgumentException("Unable to reader xml data for abstract type [" + typeof(T).Name +
                    "] because no 'Type' attribute was not specified in the element.");
            
            Type type = Type.GetType(typeAttibute);
            if (type == null)
                throw new InvalidCastException("Unable to create Task of type [" + typeAttibute + "], because it was not found.");

            if (!type.IsSubclassOf(typeof(T)))
                throw new InvalidCastException("Connection of type [" + type.Name + "] cannot be used because it does not inherit from " + typeof(T).Name + ".");

            T obj = (T)Activator.CreateInstance(type);
            obj.Id = idAttribue;
            obj.Description = descriptionAttribute;
            //now that we've read the base data pass the reader over to the Derived object to let it complete reading the data.
            obj.ReadElement(reader);

            Task = obj;
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            Type type = _task.GetType();

            writer.WriteAttributeString(TYPE_ATTRIB, type.AssemblyQualifiedName);
            writer.WriteAttributeString(DESCRIPTION_ATTRIB, Task.Description);
            writer.WriteAttributeString(ID_ATTRIB, Task.Id.ToString());

            Task.WriteElement(writer);
        }
        
        #endregion

        public static implicit operator T(TaskXmlSerializer<T> o)
        {
            return o.Task;
        }

        public static implicit operator TaskXmlSerializer<T>(T o)
        {
            return o == null ? null : new TaskXmlSerializer<T>(o);
        } 
    }
}
